﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Compilex.Automata;
using Infraestruturex.BaseLibrary;
using Infraestruturex;
using Infraestruturex.Automata;
using Infraestruturex.Automata.SPA;
using Compilex.BaseLibrary;
using Compilex;

namespace Metex
{
    public class Metex
    {
        public string Input { get; private set; }
        public string[] Rules { get; set; }

        public SyntaticAnalyzer SyntaticAnalyzer { get; private set; }

        public Metex(string input)
        {
            this.SyntaticAnalyzer = new SyntaticAnalyzer();
            this.SyntaticAnalyzer.Submachines = new SimpleHashtable<string, SPA>();
            this.SyntaticAnalyzer.SemanticActionManager = new SemanticActionManager();
            this.Rules = input.Split(new char[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
        }
        public Metex(params string[] rules)
        {
            this.SyntaticAnalyzer = new SyntaticAnalyzer();
            this.SyntaticAnalyzer.Submachines = new SimpleHashtable<string, SPA>();
            this.SyntaticAnalyzer.SemanticActionManager = new SemanticActionManager();
            this.Rules = rules;
        }

        public SyntaticAnalyzer MetaCompile()
        {
            string startRule = "";
            bool isStartRule = true;
            foreach (string rule in Rules)
            {
                RuleCompiler ruleCompiler = new RuleCompiler(rule);
                SyntaticAnalyzer.Submachines[ruleCompiler.SubmachineName] = ruleCompiler.CompileToSPA();
                if (isStartRule)
                {
                    startRule = ruleCompiler.SubmachineName;
                    isStartRule = false;
                }
            }

            SolveSubmachineCallReferences();
            AddEmptySemanticActions();

            SyntaticAnalyzer.StartSubmachine = SyntaticAnalyzer.Submachines[startRule];
            return SyntaticAnalyzer;
        }

        private void AddEmptySemanticActions()
        {
            foreach (SPA spa in SyntaticAnalyzer.Submachines.Values)
            {
                spa.SemanticActionManager = SyntaticAnalyzer.SemanticActionManager;
                SPAState[] states = spa.GetStates();
                foreach (SPAState state in states)
                {
                    foreach (var transition in state.Transitions.ToArray())
                    {
                        string actionID = SyntaticAnalyzer.SemanticActionManager.AddSemanticAction(() => { });
                        transition.SemanticActionName = actionID;
                    }
                    if (state.IsSubmachineCallState)
                    {
                        string actionID = SyntaticAnalyzer.SemanticActionManager.AddSemanticAction(() => { });
                        state.SubmachineCallSemanticActionName = actionID;
                    }
                }
            }
        }

        private void SolveSubmachineCallReferences()
        {
            SPAReferenceSolver referenceSolver = new SPAReferenceSolver(SyntaticAnalyzer.Submachines);
            foreach (var kvp in SyntaticAnalyzer.Submachines)
            {
                referenceSolver.SolveReferences(kvp.Value);
            }
        }
    }
}
